/**
 * \file AddressSpace.h
 * \brief Address space management
 * \author Corey Tabaka
 */

/*
   Copyright 2007 Corey Tabaka

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

#include <ktypes.h>
#include <Sync.h>
#include <Queue.h>
#include <platform/PageTable.h>
#include <platform/PageMap.h>

#ifndef __KERNEL_ADDRESS_SPACE_H__
#define __KERNEL_ADDRESS_SPACE_H__

#include <vm/Cache.h>

enum {
	REGION_TYPE_NA=-1,
	REGION_TYPE_NONE=0,
	REGION_TYPE_MAPPING,
	REGION_TYPE_FRAMEBUFFER,
	REGION_TYPE_MALLOC,
	REGION_TYPE_VM86,
	REGION_TYPE_EXE,
	REGION_TYPE_CODE,
	REGION_TYPE_DATA,
	REGION_TYPE_RDATA,
	REGION_TYPE_BSS,
	REGION_TYPE_HEAP,
	REGION_TYPE_STACK,
	REGION_TYPE_FILE,
	REGION_TYPE_VGA,
};

enum {
	REGION_FLAGS_CONTIG			= 0x0001,
	REGION_FLAGS_USER			= 0x0002,
	REGION_FLAGS_WIRED			= 0x0004,
	REGION_FLAGS_NOCACHE		= 0x0008,
	REGION_FLAGS_ANONYMOUS		= 0x0010,
	REGION_FLAGS_READONLY		= 0x0020,
	
	REGION_FLAGS_VM86			= REGION_FLAGS_CONTIG | REGION_FLAGS_USER
								| REGION_FLAGS_WIRED,
	
	REGION_FLAGS_EXE			= REGION_FLAGS_USER,
	
	REGION_FLAGS_CODE			= REGION_FLAGS_USER | REGION_FLAGS_READONLY,
	REGION_FLAGS_DATA			= REGION_FLAGS_USER,
	REGION_FLAGS_RDATA			= REGION_FLAGS_USER | REGION_FLAGS_READONLY,
	REGION_FLAGS_BSS			= REGION_FLAGS_USER | REGION_FLAGS_ANONYMOUS,
	REGION_FLAGS_HEAP			= REGION_FLAGS_USER | REGION_FLAGS_ANONYMOUS,
	
	REGION_FLAGS_STACK			= REGION_FLAGS_USER | REGION_FLAGS_ANONYMOUS,
};

class AddressSpace;

class Region {
	friend class AddressSpace;
	friend class Cache;
	
	protected:
	
	uint32 va;		// virtual base address of the region
	uint32 pa;		// physical base address of the region, if relevant
	
	uint32 size;	// size of the region
	uint32 type;	// region type
	uint32 flags;	// region flags
	
	Region *prev, *next;
	
	AddressSpace *addressSpace;
	
	QList cacheNode;
	RefCache cache;
	
	Region(AddressSpace *as, uint32 va, uint32 pa, uint32 size, uint32 flags,
		uint32 type);
	
	public:
	
	~Region(void);
	
	uint32 getPhysicalBase(void);
	uint32 getVirtualBase(void);
	uint32 getSize(void);
	uint32 getType(void);
	uint32 getFlags(void);
	
	Region *getNext(uint32 type=REGION_TYPE_NA);
};

class AddressSpace {
	protected:
	
	Region *head, *tail;
	
	QList leastRecentlyUsed;
	QList mostRecentlyUsed;
	
	InterruptLock lock;
	
	PageTable *pageTable;
	PageMap *pageMap;
	
	void insert(Region *);
	void remove(Region *);
	
	public:
	
	AddressSpace(void);
	AddressSpace(PageTable *pt, PageMap *pm);
	~AddressSpace(void);
	
	// handler for page fauts
	bool fault(regs_t *regs);
	
	/**
	 * Creates a region for a direct mapping from virtual to physical
	 */
	Region *create(uint32 va, uint32 pa, uint32 size, uint32 flags,
		uint32 type=REGION_TYPE_NONE);
	void destroy(Region *region);
	
	Region *map(uint32 va, uint32 pa, uint32 size, uint32 flags,
		uint32 type=REGION_TYPE_NONE);
	
	Region *findType(uint32 type);
	Region *findVirtual(uint32 va);
	Region *findPhysical(uint32 pa);
	Region *first(void);
	Region *last(void);
};	

#endif
